#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <execinfo.h>
#include <ev.h>

#include "acceptor.h"
#include "client_manager.h"

#define BACK_LOG 9

// 协调服务
static server_params_t server_coor = {
	.type = 0,
	.port = 0,
	.accept_sd = 0,
	.accept_cb = &accept_cb,
	.client_list_lock = PTHREAD_RWLOCK_INITIALIZER,
	.client_list = NULL
};

// 游戏服务
static server_params_t server_game = {
	.type = 1,
	.port = 0,
	.accept_sd = 0,
	.accept_cb = &accept_cb,
	.client_list_lock = PTHREAD_RWLOCK_INITIALIZER,
	.client_list = NULL
};

static void _backtrace(int signo) {
	void *pTrace[256];
	char **ppszMsg = NULL;
	size_t uTraceSize = 0;
	static const char szSigMsg[][256] = {
		"Received SIGSEGV",
		"Received SIGPIPE",
		"Received SIGFPE",
		"Received SIGABRT"
	};

	int eid = 0;
	switch (signo) {
	case SIGSEGV:
		eid = 0;
		break;
	case SIGPIPE:
		eid = 1;
		break;
	case SIGFPE:
		eid = 2;
		break;
	case SIGABRT:
		eid = 3;
		break;
	}

	do {
		if (0 == (uTraceSize = backtrace(pTrace, sizeof(pTrace) / sizeof(void *)))) {
			break;
		}
		if (NULL == (ppszMsg = backtrace_symbols(pTrace, uTraceSize))) {
			break;
		}

		freopen("./logs/core_dump.log", "a", stderr);

		char strtime[50]={0};
		time_t my_tm = time(NULL);
		struct tm *cur_tm = localtime(&my_tm);
		strftime(strtime, sizeof(strtime), "%Y-%m-%d %H:%M:%S", cur_tm);
		
		fprintf(stderr, "[%s]%s. call stack:\n", strtime, szSigMsg[eid]);
		size_t i;
		for (i = 0; i < uTraceSize; i++) {
			fprintf(stderr, "%s\n", ppszMsg[i]);
		}
	} while (0);

	if (NULL != ppszMsg) {
		free(ppszMsg);
		ppszMsg = NULL;
	}
}

static void _signal_handler(int signo) {
	signal(signo, SIG_DFL); /* 还原默认的信号处理handler */
	_backtrace(signo);
	exit(0);
}

static void reg_core_dump_signal_handler() {
	printf("reg_core_dump_signal_handler\n");
	signal(SIGPIPE, &_signal_handler);	// SIGPIPE，管道破裂。
	signal(SIGSEGV, &_signal_handler);	// SIGSEGV，非法内存访问
	signal(SIGFPE, &_signal_handler);	// SIGFPE，数学相关的异常，如被0除，浮点溢出，等等
	signal(SIGABRT, &_signal_handler);	// SIGABRT，由调用abort函数产生，进程非正常退出
}

// ---------------------------------------------------------------------------------
// 响应SIGINT信号
static void on_sig_int(int signo) {
	printf("---------------------------\n");
	all_clients_return(&server_coor);
	all_clients_return(&server_game);
	client_manager_release();
	printf("---------------------------\n");

	if (server_coor.accept_sd != 0) {
		close(server_coor.accept_sd);
	}
	if (server_game.accept_sd != 0) {
		close(server_game.accept_sd);
	}
	
	printf("Program exit.\n");
	exit(0);
}

void usage(const char *prog) {
	printf("usage: %s <port_coor> <port_game>\n", prog);
}

// ---------------------------------------------------------------------------------

static void * server_main_loop(void *args) {
	server_params_t *params = (server_params_t *)args;
	struct ev_loop *loop = ev_loop_new(0);
	struct sockaddr_in addr;
	
	acceptor_t acceptor;
	acceptor.params = params;

	// Create server socket
	int accept_sd;
	if ((accept_sd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket error");
		return NULL;
	}
	params->accept_sd = accept_sd;

	memset(&addr, 0x0, sizeof(struct sockaddr_in));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(params->port);
	addr.sin_addr.s_addr = INADDR_ANY;

	// Bind socket to address
	if (bind(accept_sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) != 0) {
		perror("bind error");
	}

	printf("port(%d) binded.\n", params->port);

	// Start listing on the socket
	if (listen(accept_sd, BACK_LOG) < 0) {
		perror("listen error");
		return NULL;
	}

	// Initialize and start a watcher to accepts client requests
	ev_io_init(&acceptor.watcher, params->accept_cb, accept_sd, EV_READ);
	ev_io_start(loop, &acceptor.watcher);

	// Start infinite loop
	while (1) {
		//ev_loop(loop, 0);
		ev_run(loop, 0);
	}

	return NULL;
}

// ---------------------------------------------------------------------------------
int main(int argc, char *argv[]) {
	// 标准输出不缓存
	setbuf(stdout, NULL);
	setbuf(stderr, NULL);
	
	if (argc < 3) {
		usage(argv[0]);
		exit(1);
	}

	// 注册ctrl+c响应函数
	signal(SIGINT, &on_sig_int);
	signal(SIGUSR1, &on_sig_int);

	server_coor.port = atoi(argv[1]);
	server_game.port = atoi(argv[2]);
	printf("try to bind port(%d, %d).\n", server_coor.port, server_game.port);

	client_manager_init();

	pthread_t tid_coor, tid_game;
	int ret;
	ret = pthread_create(&tid_coor, NULL, server_main_loop, (void *)&server_coor);
	if (ret != 0) {
		fprintf(stderr, "pthread_create: server_main_loop coor\n");
		exit(EXIT_FAILURE);
	}

	ret = pthread_create(&tid_game, NULL, server_main_loop, (void *)&server_game);
	if (ret != 0) {
		fprintf(stderr, "pthread_create: server_main_loop game\n");
		exit(EXIT_FAILURE);
	}

	pthread_join(tid_coor, NULL);
	pthread_join(tid_game, NULL);

	return 0;
}